home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 2 / Apprentice-Release2.iso / Source Code / C / Applications / Eudora 1.3.1 / source / tefuncs.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-03-16  |  20.0 KB  |  673 lines  |  [TEXT/MPS ]

  1. #define FILE_NUM 38
  2. /* Copyright (c) 1990-1992 by the University of Illinois Board of Trustees */
  3. #pragma load EUDORA_LOAD
  4. #pragma segment TEFuncs
  5.  
  6.     short WhichLine(TEHandle teh,int offset);
  7.     short TEFakeLotsaTabs(TEHandle teh,short selStart,short selEnd);
  8.     void TEWrap(TEHandle teh,Boolean wrap);
  9.     void DoTEsWorkForIt(TEHandle teh,short oldStart,short oldEnd,short key,short mods);
  10.     Boolean IsWordChar(Byte c);
  11.   short TabCount(TEHandle teh,short selStart,short stopDistance);
  12.     short TELineDelta(TEHandle teh, Rect *view, short line);
  13.     void ZapTEScrap(void);
  14. /**********************************************************************
  15.  * CountTeLines - figure out how many lines are in a TE rec
  16.  **********************************************************************/
  17. int CountTeLines(TEHandle teh)
  18. {
  19.     int count = (*teh)->nLines;
  20.     
  21.     if ((*teh)->teLength && (*(*teh)->hText)[(*teh)->teLength-1]=='\n')
  22.         count++;
  23.     return(count?count:1);
  24. }
  25.  
  26. /**********************************************************************
  27.  * ShowWinInsertion - show the insertion point
  28.  **********************************************************************/
  29. ShowInsertion(MyWindowPtr win,short whichEnd)
  30. {
  31.     TEHandle teh=WinTEH(win);
  32.     int dv;
  33.     
  34.     if (!teh) return;
  35.     
  36.     if (win->showInsert) (*win->showInsert)(win,whichEnd);
  37.     else if (win->ste)
  38.         STEShowInsert(win->ste);
  39.     else if (teh && (dv=TEInsertDelta(teh,&win->contR,whichEnd)))
  40.     {
  41.         HFC(win);
  42.         ScrollIt(win,0,dv);
  43.     }
  44. }
  45.  
  46. /************************************************************************
  47.  * TEInsertDelta - figure out how far a TE must scroll veritcally to show
  48.  * insertion point
  49.  ************************************************************************/
  50. short TEInsertDelta(TEHandle teh,Rect *view,short whichEnd)
  51. {
  52.     short endDv = TELineDelta(teh,view,WhichLine(teh,(*teh)->selEnd));
  53.     short startDv = TELineDelta(teh,view,WhichLine(teh,(*teh)->selStart));
  54.     
  55.     if (whichEnd==InsertStart) return(startDv);
  56.     else if (whichEnd==InsertEnd) return(endDv);
  57.     else if (endDv*startDv <= 0) return(0);    /* part of it is already visible */
  58.     return(startDv);                                                /* prefer the top */
  59. }
  60.  
  61. /************************************************************************
  62.  * TELineDelta - how far do we need to scroll to show a given line?
  63.  ************************************************************************/
  64. short TELineDelta(TEHandle teh, Rect *view, short line)
  65. {
  66.     short top,bottom,dv=0;
  67.     short hi = (*teh)->lineHeight;
  68.     
  69.     top = (*teh)->destRect.top+line*hi;
  70.     bottom = top + hi;
  71.     if (bottom > view->bottom)
  72.         dv = -((bottom - (view->bottom-view->top)/2 - 1)/hi);
  73.     else if (top < view->top)
  74.         dv = ((view->bottom-view->top)/2 - top - 1)/hi;
  75.     return(dv);
  76. }
  77.  
  78.  
  79. /************************************************************************
  80.  * HFC - Hide Foolish Caret
  81.  ************************************************************************/
  82. void HFC(MyWindowPtr win)
  83. {
  84.     if (win && win->qWindow.windowKind>=userKind && win->isActive)
  85.     {
  86.         TEHandle teh=WinTEH(win);
  87.         
  88.         if (teh && !win->hasSelection && (*teh)->caretState==-1)
  89.         {
  90.             TEIdle(teh);
  91.             (*teh)->caretState = 255;
  92.             ERASE_RECT(&(*teh)->selRect);
  93.             INVAL_RECT(&(*teh)->selRect);
  94.         }
  95.     }
  96. }
  97.  
  98. /************************************************************************
  99.  * TESomething - perform one of the TE functions
  100.  ************************************************************************/
  101. Boolean TESomething(MyWindowPtr win,TEEnum what,short key,short mods)
  102. {
  103.     int oldNl;                        /* number of lines before we did bad things */
  104.     int newNl;                        /* ditto, but after */
  105.     TEHandle teh=WinTEH(win);
  106.     int oldBytes, newStart, newEnd;
  107.     MessType **messH = (MessType **)((WindowPeek)win)->refCon; /* maybe */
  108.     short err,beginLine;
  109.     Boolean dirty=False;
  110.     short oldStart = (*teh)->selStart;
  111.     short oldEnd = (*teh)->selEnd;
  112.     short len;
  113.     long junk;
  114.     short whichEnd = InsertAny;
  115.     
  116.     if (what!=TECUT && what!=TECLEAR && what!=TECOPY && what!=TEPASTE &&
  117.             what!=TEQPASTE && what!=TEKEY && what!=TEWRAP && what!=TEUNWRAP) return(False);
  118.     oldNl = CountTeLines(teh);
  119.     if (win->isActive)
  120.         if (what!=TEKEY || DirtyKey(key))
  121.             TEPrepareUndo(win,what);
  122.         else
  123.             Undo.didClick = True;
  124.     switch (what)
  125.     {
  126.         case TECUT:
  127.             dirty = (*teh)->selStart != (*teh)->selEnd;
  128.             TECut(teh);
  129.             if ((err=ZeroScrap()) || (err=TEToScrap()))
  130.                 WarnUser(CUT_FAILED,err);
  131.                 ZapTEScrap();
  132.             break;
  133.         case TECLEAR:
  134.             dirty = (*teh)->selStart != (*teh)->selEnd;
  135.             if (win->ro)
  136.             {
  137.                 if (SumOf((MessHandle)win->qWindow.refCon)->state!=SENT)
  138.                 {
  139.                     TEDelete(teh);
  140.                     AttachSelect(teh);
  141.                 }
  142.             }
  143.             else
  144.                 TEDelete(teh);
  145.             break;
  146.         case TEWRAP:
  147.         case TEUNWRAP:
  148.             TEWrap(teh,what==TEWRAP);
  149.             dirty = True;
  150.             break;
  151.         case TECOPY:
  152.             TECopy(teh);
  153.             if ((err=ZeroScrap()) || (err=TEToScrap()))
  154.                 WarnUser(COPY_FAILED,err);
  155.             ZapTEScrap();
  156.             break;
  157.         case TEPASTE:
  158.             len = GetScrap(nil,'TEXT',&junk);
  159.             if (len>0 && (*teh)->teLength+len-oldEnd+oldStart>INFINITY)
  160.                 WarnUser(TE_TOO_MUCH,0);
  161.             else if (len<=0 || (err=TEFromScrap()))
  162.                 WarnUser(PASTE_FAILED,len<0?len:err);
  163.             else
  164.             {
  165.                 TEPaste(teh); ZapTEScrap();
  166.                 newEnd = (*teh)->selEnd;
  167.                 if (FakeTabs && (win->qWindow.windowKind!=COMP_WIN||
  168.                     (*(*messH)->tocH)->sums[(*messH)->sumNum].flags&FLAG_TABS))
  169.                 {
  170.                     newEnd += TEFakeLotsaTabs(teh,oldStart,newEnd);
  171.                     NoScrollTESetSelect(newEnd,newEnd,teh);
  172.                 }
  173.                 dirty = True;
  174.             }
  175.             break;
  176.         case TEQPASTE:
  177.             len = GetScrap(nil,'TEXT',&junk);
  178.             if (len>0 && (*teh)->teLength+len-oldEnd+oldStart>INFINITY)
  179.                 WarnUser(TE_TOO_MUCH,0);
  180.             else if (len<=0 || (err=TEFromScrap()))
  181.                 WarnUser(PASTE_FAILED,err);
  182.             else
  183.             {
  184.                 newStart = (*teh)->selStart;
  185.                 TEPaste(teh); ZapTEScrap();
  186.                 newEnd = (*teh)->selEnd;
  187.                 oldBytes = (*teh)->teLength;
  188.                 beginLine = WhichLine(teh,newStart);
  189.                 if (newStart && (*(*teh)->hText)[newStart-1]!='\n') beginLine++;
  190.                 QuoteLines(messH,FindCompTx(messH,teh),
  191.                     beginLine,WhichLine(teh,newEnd-1),QUOTE_PREFIX);
  192.                 newEnd += (*teh)->teLength - oldBytes;
  193.                 if (FakeTabs && (win->qWindow.windowKind!=COMP_WIN||
  194.                     (*(*messH)->tocH)->sums[(*messH)->sumNum].flags&FLAG_TABS))
  195.                     newEnd += TEFakeLotsaTabs(teh,oldStart,newEnd);
  196.                 NoScrollTESetSelect(newEnd,newEnd,teh);
  197.                 dirty = true;
  198.             }
  199.             break;
  200.         case TEKEY:
  201.             if (key==enterChar) key = returnChar;
  202.             if (key==delChar)
  203.             {
  204.                 dirty = True;
  205.                 if ((*teh)->selStart!=(*teh)->selEnd)
  206.                     TEKey(backSpace,teh);
  207.                 else if ((*teh)->selStart<(*teh)->teLength)
  208.                 {
  209.                     Byte undoChar = (*(*teh)->hText)[(*teh)->selStart];
  210.                     TEDeactivate(teh);
  211.                     NoScrollTESetSelect((*teh)->selStart,(*teh)->selStart+1,teh);
  212.                     TEKey(backSpace,teh);
  213.                     TEActivate(teh);
  214.                     /*
  215.                      * append the deleted char to the undo buffer
  216.                      */
  217.                     if (!Undo.text) Undo.text = NewHandle(0);
  218.                     if (!Undo.text || PtrAndHand(&undoChar,Undo.text,1))
  219.                         WarnUser(WONT_UNDO,MemError());
  220.                 }
  221.                 else
  222.                     dirty = False;
  223.             }
  224.             else
  225.             {
  226.                 if (key==backSpace &&
  227.                         (*teh)->selStart==(*teh)->selEnd && (*teh)->selEnd &&
  228.                         (*teh)->selStart == Undo.startFrom)
  229.                 {
  230.                     /*
  231.                      * prepend undoChar to Undo buffer
  232.                      */
  233.                     Byte undoChar = (*(*teh)->hText)[(*teh)->selStart-1];
  234.                     if (!Undo.text) Undo.text = NewHandle(0);
  235.                     if (!Undo.text || PtrAndHand(&undoChar,Undo.text,1))
  236.                         WarnUser(WONT_UNDO,MemError());
  237.                     BlockMove(*Undo.text,(*Undo.text)+1,GetHandleSize(Undo.text)-1);
  238.                     **Undo.text = undoChar;
  239.                     Undo.startFrom--;
  240.                 }
  241.                 
  242.                 /* make TE down arrow do the right thing */
  243.                 if (!(mods&optionKey) && key==downArrowChar) TESetSelect(oldEnd,oldEnd,teh);
  244.                 
  245.                 /*
  246.                  * pass key to TE
  247.                  */
  248.                 TEKey(key,teh);
  249.                 
  250.                 /* post-processing */
  251.                 dirty = DirtyKey(key);
  252.                 if (!dirty) Undo.didClick = True;
  253.                 if (key>=leftArrowChar && key<=downArrowChar)
  254.                 {
  255.                     if (mods&(shiftKey|optionKey))
  256.                         DoTEsWorkForIt(teh,oldStart,oldEnd,key,mods);
  257.                     whichEnd = (key==leftArrowChar||key==upArrowChar) ?
  258.                                             InsertStart:InsertEnd;
  259.                 }
  260.             }
  261.             break;
  262.     }
  263.     if (win->isActive && Undo.teh && dirty) Undo.goTil = (*Undo.teh)->selEnd;
  264.     if (dirty)
  265.     {
  266.         newNl = CountTeLines(teh);
  267.         win->isDirty = True;
  268.         if (win->textChanged) (*win->textChanged)(win,teh,oldNl,newNl);
  269.     }
  270.     ShowInsertion(win,whichEnd);
  271.     return(True);
  272. }
  273.  
  274. /************************************************************************
  275.  * OffsetTE - move the terecs around in a window
  276.  ************************************************************************/
  277. void OffsetTE(MyWindowPtr win,TEHandle teh,short offset)
  278. {
  279.     MessType **messH = (MessType **)((WindowPeek)win)->refCon;
  280.     short tx = FindCompTx(messH,teh);
  281.     OFFSET_RECT(&(*teh)->destRect,0,offset);
  282.     OFFSET_RECT(&(*teh)->selRect,0,offset);
  283.     
  284.     (*teh)->viewRect.top = MAX((*teh)->destRect.top,win->contR.top);
  285.     (*teh)->viewRect.bottom = tx==HEAD_LIMIT-1 ? win->contR.bottom :
  286.                                                          MIN((*teh)->destRect.bottom,win->contR.bottom);
  287. }
  288.  
  289. /************************************************************************
  290.  * WhichLine - which line is an offset on?
  291.  ************************************************************************/
  292. short WhichLine(TEHandle teh,int offset)
  293. {
  294.     short which;
  295.     
  296.     for (which=0;which<(*teh)->nLines;which++)
  297.         if ((*teh)->lineStarts[which]>offset) break;
  298.     return(which-1);
  299. }
  300.  
  301. /************************************************************************
  302.  * TEWordSelect - force the selection to consist of integral words
  303.  ************************************************************************/
  304. void TEWordSelect(TEHandle teh)
  305. {
  306.     UPtr start, end, selStart, selEnd;
  307.     
  308.     start = *(*teh)->hText;
  309.     selStart = start + (*teh)->selStart;
  310.     selEnd = start + (*teh)->selEnd;
  311.     end = start + (*teh)->teLength;
  312.     
  313.     /*
  314.      * extend until the char before it is a space
  315.      */
  316.     while (selStart>start && selStart[-1]!=' ') selStart--;
  317.     
  318.     /*
  319.      * extend until char after is a space
  320.      */
  321.     while (selEnd < end && *selEnd!=' ') selEnd++;
  322.     
  323.     /*
  324.      * set it
  325.      */
  326.     NoScrollTESetSelect(selStart-start,selEnd-start,teh);
  327. }
  328.  
  329. /************************************************************************
  330.  * TEFakeTab - fake a tab stop by inserting an appropriate number of spaces
  331.  ************************************************************************/
  332. short TEFakeTab(MyWindowPtr win,short stopDistance)
  333. {
  334.     short i,count;
  335.     TEHandle teh=WinTEH(win);
  336.     
  337.     count = i = TabCount(teh,(*teh)->selStart,stopDistance);
  338.     while (i--)
  339.         TESomething(win,TEKEY,' ',0);
  340.     return(count);
  341. }
  342.  
  343.  
  344. /************************************************************************
  345.  * TabCount - how many spaces do we need here for a tab?
  346.  ************************************************************************/
  347. short TabCount(TEHandle teh,short selStart,short stopDistance)
  348. {
  349.     UPtr spot;
  350.     short count;
  351.  
  352.     spot = *(*teh)->hText + selStart - 1;
  353.     while (*spot != '\n' && spot>=*(*teh)->hText) spot--;
  354.     count = selStart - (spot-*(*teh)->hText) - 1;
  355.     count = stopDistance - count%stopDistance;
  356.     return(count);
  357. }
  358.  
  359. /************************************************************************
  360.  * TEFakeLotsaTabs - take char of tabs during paste
  361.  *  (but make the user pay <evil laugh>)
  362.  ************************************************************************/
  363. short TEFakeLotsaTabs(TEHandle teh,short selStart,short selEnd)
  364. {
  365.     short newEnd = selEnd;
  366.     short stopDistance = GetRLong(TAB_DISTANCE);
  367.     short count;
  368.     Str31 spaces;
  369.     long len = (*teh)->teLength;
  370.     
  371.     memset(spaces,' ',stopDistance);
  372.     
  373.     for (;selStart<newEnd;selStart++)
  374.         if ((*(*teh)->hText)[selStart]==tabChar)
  375.         {
  376.             count = TabCount(teh,selStart,stopDistance);
  377.             if (len+count-1>INFINITY) {WarnUser(TE_TOO_MUCH,0); break;}
  378.             if (0>Munger((*teh)->hText,selStart,nil,1,spaces,count))
  379.                 {WarnUser(PASTE_FAILED,0);break;}
  380.             newEnd += count-1;
  381.             selStart += count-1;
  382.             len += count-1;
  383.         }
  384.     if (newEnd!=selEnd)
  385.     {
  386.         len = GetHandleSize((*teh)->hText);
  387.         (*teh)->teLength = len;
  388.         INVAL_RECT(&(*teh)->viewRect);
  389.         NoScrollTECalText(teh);
  390.         NoScrollTESetSelect(newEnd,newEnd,teh);
  391.         UpdateMyWindow((*teh)->inPort);
  392.     }
  393.     return(newEnd-selEnd);
  394. }
  395.  
  396. /************************************************************************
  397.  * InsertCommaIfNeedBe - put a comma after previous address, if one is
  398.  * not there
  399.  ************************************************************************/
  400. void InsertCommaIfNeedBe(MyWindowPtr win)
  401. {
  402.     UPtr spot, end, begin;
  403.     TEHandle teh=WinTEH(win);
  404.     
  405.     begin=*(*teh)->hText;
  406.     end = begin + (*teh)->teLength;
  407.     spot = begin + (*teh)->selStart - 1;
  408.     
  409.     while (spot>=begin && *spot==' ') spot--;
  410.     if (spot>=begin && *spot!=',')
  411.     {
  412.         TESomething(win,TEKEY,',',0);
  413.         TESomething(win,TEKEY,' ',0);
  414.     }
  415. }
  416.  
  417. /************************************************************************
  418.  * TEFixup - fix up a terec with the right fonts, etc.
  419.  ************************************************************************/
  420. void TEFixup(TEHandle teh)
  421. {
  422.     if (teh)
  423.     {
  424.         (*teh)->txFont = FontID;
  425.         (*teh)->txSize = FontSize;
  426.         (*teh)->lineHeight = FontLead;
  427.         (*teh)->fontAscent = FontAscent;
  428.         
  429.         TECalText(teh);
  430.     }
  431. }
  432.  
  433. /************************************************************************
  434.  * TEMaxLine - fine the longest line in a TERec
  435.  ************************************************************************/
  436. short TEMaxLine(TEHandle teh)
  437. {
  438.     short *this,*last,max;
  439.     
  440.     max = 0;
  441.     this=(*teh)->lineStarts;
  442.     last = this+(*teh)->nLines;
  443.     for (this++;this<last;this++) if (this[0]-this[-1]>max)
  444.         max = this[0]-this[-1];
  445.     if ((*teh)->nLines && (*teh)->teLength-last[-1]>max)
  446.         max = (*teh)->teLength-last[-1];
  447.     return(max);
  448. }
  449.  
  450.  
  451. /************************************************************************
  452.  * TopOffset - what's the offset at the top of the TE?
  453.  ************************************************************************/
  454. short TopOffset(TEHandle teh)
  455. {
  456.     short linesOffTop = RoundDiv((*teh)->viewRect.top-(*teh)->destRect.top,(*teh)->lineHeight);
  457.     return((*teh)->lineStarts[linesOffTop]);
  458. }
  459.  
  460. /************************************************************************
  461.  * MakeTopOffset - put the given offset at the top of the window, if possible
  462.  ************************************************************************/
  463. void MakeTopOffset(TEHandle teh,short offset)
  464. {
  465.     short linesOffTop = RoundDiv((*teh)->viewRect.top-(*teh)->destRect.top,(*teh)->lineHeight);
  466.     short lineIs = WhichLine(teh,offset);
  467.     
  468.     TEPinScroll(0,(*teh)->lineHeight*(linesOffTop-lineIs),teh);
  469. }
  470.  
  471. /************************************************************************
  472.  * TEWrap - wrap the current selection
  473.  ************************************************************************/
  474. void TEWrap(TEHandle teh,Boolean wrap)
  475. {
  476.     void *oldSendWDS;
  477.     short oldSize, newSize;
  478.     if (WrapHandle = NuHandle(0))
  479.     {
  480.         oldSendWDS = SendWDS;
  481.         SendWDS = WrapSendWDS;
  482.         if (wrap)
  483.             SendBodyLines((*teh)->hText,(*teh)->selEnd,(*teh)->selStart,True,True,nil,0,False);
  484.         else
  485.         {
  486.             UnwrapSave(LDRef((*teh)->hText),(*teh)->selEnd,(*teh)->selStart,0);
  487.             UL((*teh)->hText);
  488.         }
  489.         if (WrapHandle)
  490.         {
  491.             oldSize = (*teh)->selEnd-(*teh)->selStart;
  492.             newSize = GetHandleSize(WrapHandle);
  493.             Munger((*teh)->hText,(*teh)->selStart,nil,oldSize,LDRef(WrapHandle),newSize);
  494.             (*teh)->teLength += GetHandleSize((*teh)->hText);
  495.             (*teh)->selEnd += newSize - oldSize;
  496.             TECalText(teh);
  497.             InvalContent((*teh)->inPort);
  498.         }
  499.         SendWDS = oldSendWDS;
  500.         ZapHandle(WrapHandle);    
  501.     }
  502. }
  503.  
  504. /************************************************************************
  505.  * WrapSendWDS - accumulate "sent" text.
  506.  ************************************************************************/
  507. int WrapSendWDS(wdsEntry *theWDS)
  508. {
  509.     short err=0;
  510.  
  511.     if (WrapHandle)
  512.     {
  513.         for (;!err && theWDS->length;theWDS++)
  514.         {
  515.             if (theWDS->length == *NewLine && !strncmp(theWDS->ptr,NewLine+1,*NewLine))
  516.                 err = PtrAndHand("\n",WrapHandle,1);
  517.             else
  518.                 err = PtrAndHand(theWDS->ptr,WrapHandle,theWDS->length);
  519.         }
  520.     }
  521.     if (err) ZapHandle(WrapHandle);
  522.     return(err);
  523. }
  524.  
  525. /************************************************************************
  526.  * TESelPara - extend the current selection to include whole paragraphs
  527.  ************************************************************************/
  528. void TESelPara(TEHandle teh)
  529. {
  530.   UPtr begin,end,selStart,selEnd;
  531.     
  532.     begin = *(*teh)->hText;
  533.     end = begin+(*teh)->teLength;
  534.     selStart = begin+(*teh)->selStart;
  535.     selEnd = begin+MAX(1,(*teh)->selEnd);
  536.     
  537.     for (;selStart>begin;selStart--) {if (selStart[-1]=='\n') break;}
  538.     for (;selEnd<end;selEnd++) if (selEnd[-1]=='\n') break;
  539.     if (selStart!=begin+(*teh)->selStart || selEnd!=begin+(*teh)->selEnd)
  540.         NoScrollTESetSelect(selStart-begin,selEnd-begin,teh);
  541. }
  542.  
  543. /************************************************************************
  544.  * DoTEsWorkForIt - handle standard text selection stuff.  TE is the only
  545.  * place this can be done easily.  Hack, hack, kludge, kludge, O what
  546.  * fun maccing is.  Hack, hack, kludge, kludge...
  547.  ************************************************************************/
  548. void DoTEsWorkForIt(TEHandle teh,short oldStart,short oldEnd,short key,short mods)
  549. {
  550.     Boolean shift = (mods&shiftKey)!=0;
  551.     Boolean option = (mods&optionKey)!=0;
  552.     Boolean wasWord;
  553.     short newStart=(*teh)->selStart,newEnd=(*teh)->selEnd;
  554.     
  555.     switch(key)
  556.     {
  557.         case downArrowChar:
  558.             /*
  559.              * TextEdit does something really stupid here; fix it up
  560.             if (WhichLine(teh,oldStart)!=WhichLine(teh,oldEnd))
  561.             {
  562.                 NoScrollTESetSelect(oldEnd,oldEnd,teh);
  563.                 TEKey(downArrowChar,teh);
  564.                 newEnd = (*teh)->selEnd;
  565.             }
  566.              */
  567.             /* Well, we've explained life to TextEdit now. */
  568.             if (shift) newStart = oldStart;
  569.             break;
  570.             
  571.         case upArrowChar:
  572.             if (shift) newEnd = oldEnd;
  573.             break;
  574.             
  575.         case leftArrowChar:
  576.             if (option)
  577.             {
  578.                 wasWord = IsWordChar((*(*teh)->hText)[oldStart-1]);
  579.                 newStart = oldStart;
  580.                 while (newStart && wasWord==IsWordChar((*(*teh)->hText)[newStart-1]))
  581.                     newStart--;
  582.                 if (newStart && !wasWord)
  583.                     while (newStart && IsWordChar((*(*teh)->hText)[newStart-1]))
  584.                         newStart--;
  585.                 if (!shift) newEnd = newStart;
  586.             }
  587.             if (shift) newEnd = oldEnd;
  588.             break;
  589.             
  590.         case rightArrowChar:
  591.             if (option)
  592.             {
  593.                 wasWord = IsWordChar((*(*teh)->hText)[oldEnd]);
  594.                 newEnd = oldEnd;
  595.                 while (newEnd<(*teh)->teLength && wasWord==IsWordChar((*(*teh)->hText)[newEnd]))
  596.                     newEnd++;
  597.                 if (oldStart && !wasWord)
  598.                     while (newEnd<(*teh)->teLength && IsWordChar((*(*teh)->hText)[newEnd]))
  599.                         newEnd++;
  600.                 if (!shift) newStart = newEnd;
  601.             }
  602.             if (shift) newStart = oldStart;
  603.             break;
  604.     }
  605.     
  606.     if (newStart==newEnd)
  607.     {
  608.         TEDeactivate(teh);
  609.         (*teh)->clikStuff = key==rightArrowChar ? 0 : 255;
  610.     }
  611.     ((MyWindowPtr)(*teh)->inPort)->hasSelection = newStart!=newEnd;
  612.     NoScrollTESetSelect(newStart,newEnd,teh);
  613.     TEActivate(teh);
  614. }
  615.  
  616. /************************************************************************
  617.  * IsWordChar - is the selected character part of a word?
  618.  ************************************************************************/
  619. Boolean IsWordChar(Byte c)
  620. {
  621.     return(c>' ');    /* this isn't internationally correct, but it's
  622.                                                      what TE does.  Sort of. */
  623. }
  624.  
  625. /************************************************************************
  626.  * NoScrollTECalText - TECalText, but without the autoscroll
  627.  ************************************************************************/
  628. void NoScrollTECalText(TEHandle teh)
  629. {
  630.     MyWindowPtr win = (*teh)->inPort;
  631.     TEAutoView(False,teh);
  632.     TECalText(teh);
  633.     if (win->qWindow.windowKind != COMP_WIN) TEAutoView(True,teh);
  634. }
  635.  
  636. /************************************************************************
  637.  * NoScrollTESetSelect - TESetSelect, but without the autoscroll
  638.  ************************************************************************/
  639. void NoScrollTESetSelect(short start,short end,TEHandle teh)
  640. {
  641.     MyWindowPtr win = (*teh)->inPort;
  642.     TEAutoView(False,teh);
  643.     TESetSelect(start,end,teh);
  644.     if (win->qWindow.windowKind != COMP_WIN) TEAutoView(True,teh);
  645. }
  646.  
  647. /************************************************************************
  648.  * TELineOf - figure out which line a selection falls on
  649.  ************************************************************************/
  650. short TELineOf(short position, TEHandle teh)
  651. {
  652.     short line;
  653.     
  654.     for (line=0;line<(*teh)->nLines;line++)
  655.         if ((*teh)->lineStarts[line] > position) break;
  656.     if (line==(*teh)->nLines) line--;
  657.     
  658.     return(line);
  659. }
  660.  
  661. /************************************************************************
  662.  * ZapTEScrap - get rid of the horrid monster te scrap
  663.  ************************************************************************/
  664. void ZapTEScrap(void)
  665. {
  666.     Handle h = TEScrapHandle();
  667.     if (h)
  668.     {
  669.         SetHandleSize(h,0);
  670.         TESetScrapLen(0);
  671.     }
  672. }
  673.